/**
 * Copyright (C), 2015-2024, XXX有限公司
 * FileName: Util
 * Author:   mac
 * Date:     2024/3/18 16:02
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.finsiot.tools.taos.migration;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author zhangtianchang
 * @create 2024/3/18
 * @since 1.0.0
 */
@Slf4j
public class Util {

    static final int maxLine=200000;
    static BufferedWriter output;
    static  List<String> valueList = new ArrayList<>();
    static  ResultSet rs;
    static  String sql;
    static ResultSetMetaData metaData;

    static String columnName;

    static String sqlLine;

    static File dataFile;

    public static void tableWrite2File(Statement statement, String stable, List<String> filedList,List<String> tagList,List<String> tagValueList, String filePath, int days, String precision) {
        try {

            long count=0L;
            rs=statement.executeQuery("select count(*) from " + stable +" where ts > (now()-"+days+"d)");
            if(!rs.next()){
                return;
            }else {
                count= rs.getLong(1);
            }

            long start=0L;
            int n=0;
            do {
                sql = "select * from " + stable + " where ts > (now()-" + days + "d) limit " + start + "," + maxLine;

                if (n == 0) {
                    dataFile = new File(String.format(filePath + "/data/%s/%s.sql", stable,stable));
                    //生成文件
                    dataFile.delete();
                    if (!dataFile.getParentFile().exists()) {
                        dataFile.getParentFile().mkdir();
                    }
                } else {
                    dataFile = new File(String.format(filePath + "/data/%s/%s-%d.sql", stable,stable, n));
                    dataFile.delete();
                }

                output = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(dataFile.toPath()), StandardCharsets.UTF_8), 1024);
                stableWrite2File(statement, stable, filedList,tagList,tagValueList, precision, sql);
                output.flush();
                output.close();

                n++;
                start += maxLine;
            } while (start <= count);


            log.info("表:{}导出数据完成,file: {}\n", stable, dataFile.getAbsoluteFile());
        } catch (SQLException | IOException e) {
            log.error(e.getMessage());
        }
    }


    private static void stableWrite2File(Statement statement,String stable,List<String> filedList,List<String> tagList,List<String> tagValueList,String precision,String sql) throws IOException, SQLException {

        rs = statement.executeQuery(sql);

        //获取元数据信息
        metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        log.info("execute sql：{}", sql);

        while (rs.next()) {

            for (int i = 0; i < columnCount; i++) {
                columnName = metaData.getColumnName(i+1);
                if(filedList.contains(columnName)) {

                    if(rs.getObject(columnName)==null){
                        valueList.add("NULL");
                    }else {
                        switch (metaData.getColumnType(i + 1)) {

                            case Types.TIMESTAMP:
                                Timestamp value = rs.getTimestamp(columnName);

                                SimpleDateFormat format = null;
                                if (precision.equalsIgnoreCase("ms")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                                }
                                if (precision.equalsIgnoreCase("us")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
                                }

                                if (precision.equalsIgnoreCase("ns")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSSSS");
                                }
                                valueList.add("'" + format.format(value) + "'");
                                break;
                            case Types.DATE:
                                valueList.add("'" + new SimpleDateFormat("yyyy-MM-dd").format(rs.getDate(columnName)) + "'");
                                break;
                            case Types.INTEGER:
                                valueList.add(Integer.toString(rs.getInt(columnName)));
                                break;
                            case Types.BIGINT:
                            case Types.NUMERIC:
                                valueList.add(Long.toString(rs.getLong(columnName)));
                                break;
                            case Types.DECIMAL:
                                valueList.add(rs.getBigDecimal(columnName).toString());
                                break;
                            case Types.FLOAT:
                                valueList.add(Float.toString(rs.getFloat(columnName)));
                                break;
                            case Types.DOUBLE:
                                valueList.add(Double.toString(rs.getDouble(columnName)));
                                break;
                            case Types.NULL:
                                valueList.add("''");
                                break;
                            case Types.NCHAR:
                                valueList.add("'" + rs.getNString(columnName) + "'");
                                break;
                            case Types.BOOLEAN:
                                valueList.add("'" + rs.getBoolean(columnName) + "'");
                                break;
                            case Types.BINARY:
                            case Types.VARBINARY:
                                byte[] binary = rs.getBytes(i);
                                valueList.add("'" + Base64.encodeBase64String(binary) + "'");
                                break;
                            default:
                                log.error("字段：{}类型：{}还不支持导出\n", columnName, metaData.getColumnTypeName(i + 1));

                        }
                    }

                }
            }
            sqlLine = "INSERT INTO " + stable +
                    " (`" +
                    StringUtils.join(filedList, "`,`") +
                    "`) VALUES(" +
                    StringUtils.join(valueList, ",") +
                    ");\n";

            //将数据写入到 sb中， 逗号分隔
            output.write(sqlLine);
            valueList.clear();
        }

        rs.close();

    }
    public static void tableWrite2File(Statement statement, String stable, String table, List<String> filedList,List<String> tagList,List<String> tagValueList, String filePath, int days, String precision) {

        try {

            long count=0L;
            rs=statement.executeQuery("select count(*) from " + table +" where ts > (now()-"+days+"d)");
            if(!rs.next()){
                return;
            }else {
                count= rs.getLong(1);
            }

            long start=0L;
            int n=0;
            do {
                sql = "select * from " + table + " where ts > (now()-" + days + "d) limit " + start + "," + maxLine;

                if (n == 0) {
                    dataFile = new File(String.format(filePath + "/data/%s/%s.sql", stable,table));
                    //生成文件
                    dataFile.delete();
                    if (!dataFile.getParentFile().exists()) {
                        dataFile.getParentFile().mkdir();
                    }
                } else {
                    dataFile = new File(String.format(filePath + "/data/%s/%s-%d.sql", stable,table, n));
                    dataFile.delete();
                }

                output = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(dataFile.toPath()), StandardCharsets.UTF_8), 1024);
                write2File(statement, stable, table, filedList,tagList,tagValueList, precision, sql);
                output.flush();
                output.close();

                n++;
                start += maxLine;
            } while (start <= count);


            log.info("表:{}导出数据完成,file: {}\n", table, dataFile.getAbsoluteFile());
        } catch (SQLException | IOException e) {
            log.error(e.getMessage());
        }

    }


    private static void write2File(Statement statement,String stable,String table,List<String> filedList,List<String> tagList,List<String> tagValueList,String precision,String sql) throws IOException, SQLException {
        rs = statement.executeQuery(sql);

        //获取元数据信息
        metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();
        log.info("execute sql：{}", sql);

        while (rs.next()) {

            for (int i = 0; i < columnCount; i++) {
                columnName = metaData.getColumnName(i+1);
                if(filedList.contains(columnName)) {

                    if(rs.getObject(columnName)==null){
                        valueList.add("NULL");
                    }else {
                        switch (metaData.getColumnType(i + 1)) {

                            case Types.TIMESTAMP:
                                Timestamp value = rs.getTimestamp(columnName);

                                SimpleDateFormat format = null;
                                if (precision.equalsIgnoreCase("ms")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                                }
                                if (precision.equalsIgnoreCase("us")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
                                }

                                if (precision.equalsIgnoreCase("ns")) {
                                    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSSSS");
                                }
                                valueList.add("'" + format.format(value) + "'");
                                break;
                            case Types.DATE:
                                valueList.add("'" + new SimpleDateFormat("yyyy-MM-dd").format(rs.getDate(columnName)) + "'");
                                break;
                            case Types.INTEGER:
                                valueList.add(Integer.toString(rs.getInt(columnName)));
                                break;
                            case Types.BIGINT:
                            case Types.NUMERIC:
                                valueList.add(Long.toString(rs.getLong(columnName)));
                                break;
                            case Types.DECIMAL:
                                valueList.add(rs.getBigDecimal(columnName).toString());
                                break;
                            case Types.FLOAT:
                                valueList.add(Float.toString(rs.getFloat(columnName)));
                                break;
                            case Types.DOUBLE:
                                valueList.add(Double.toString(rs.getDouble(columnName)));
                                break;
                            case Types.NULL:
                                valueList.add("''");
                                break;
                            case Types.NCHAR:
                                valueList.add("'" + rs.getNString(columnName) + "'");
                                break;
                            case Types.BOOLEAN:
                                valueList.add("'" + rs.getBoolean(columnName) + "'");
                                break;
                            case Types.BINARY:
                            case Types.VARBINARY:
                                byte[] binary = rs.getBytes(i);
                                valueList.add("'" + Base64.encodeBase64String(binary) + "'");
                                break;
                            default:
                                log.error("字段：{}类型：{}还不支持导出\n", columnName, metaData.getColumnTypeName(i + 1));

                        }
                    }

                }
            }
            sqlLine = "INSERT INTO " + table +
                    " USING " +
                    stable +
                    "(`" +
                    StringUtils.join(tagList, "`,`") +
                    "`)" +
                    " TAGS ('" +
                    StringUtils.join(tagValueList, "','") +
                    "') (`" +
                    StringUtils.join(filedList, "`,`") +
                    "`) VALUES(" +
                    StringUtils.join(valueList, ",") +
                    ");\n";

            //将数据写入到 sb中， 逗号分隔
            output.write(sqlLine);
            valueList.clear();
        }

        rs.close();
    }
}